package suncertify.db.file;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DataFileReader {

    private String[] hotelData;
    /** The bytes that store the "magic cookie" value */
    private static final int MAGIC_COOKIE_BYTES = 64;
    /** The bytes that store the total overall length of each record */
    private static final int RECORD_LENGTH_BYTES = 4;
    /** The bytes that store the number of fields in each record */
    private static final int NUMBER_OF_FIELDS_BYTES = 2;
    /** The bytes that store the length of each field name */
    private static final int FIELD_NAME_BYTES = 2;
    /** The bytes that store the fields length */
    private static final int FIELD_LENGTH_BYTES = 2;
    /** The bytes that store the flag of each record */
    private static final int RECORD_FLAG_BYTES = 1;
    /** The value that identifies a record as being valid */
    private static final int VALID = 0;
    /** The .db file location */
    private static final String DATABASE_LOCATION = "D:\\Entwicklung\\SCJD\\Certification\\Aufgabe\\File\\db-1x1.db";
    /** The character encoding of the file */
    private static final String ENCODING = "US-ASCII";

    public DataFileReader() {
	try {
	    readDirectly();
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
    }

    /**
     * Reads the .db file. The values are read according to the information
     * provided in the class-level fields (such as MAGIC_COOKIE_BYTES) and to
     * values read at runtime (such as field name length). Each relevant value
     * is displayed on the console in the form "Field: value". For instance:
     * 
     * <pre>
     * Magic cookie: 888
     * Record length: 888
     * Number of fields in each record: 8
     * </pre>
     * 
     * The content of each record is displayed until EOF is reached.
     * 
     * @param args
     *            The arguments provided in the command line when this
     *            application is run.
     */
    public static void main(final String[] args) throws IOException {
	DataFileReader reader = new DataFileReader();
	reader.read();
	// int arrayLength = raf.readShort();
	// byte[] newArr2 = new byte[arrayLength];
	// raf.read(newArr2);
	// String s = new String(newArr2, ENCODING);
	// System.out.println(s);
	//
	// int arrayLength2 = raf.readShort();
	// byte[] newArr3 = new byte[arrayLength2];
	// raf.read(newArr3);
	// String st = new String(newArr3, ENCODING);
	// System.out.println(st);

	// try {
	// final InputStream database = new FileInputStream(DATABASE_LOCATION);
	//
	// final byte[] magicCookieByteArray = new byte[MAGIC_COOKIE_BYTES];
	// final byte[] recordLengthByteArray = new byte[RECORD_LENGTH_BYTES];
	// final byte[] numberOfFieldsByteArray = new
	// byte[NUMBER_OF_FIELDS_BYTES];
	//
	// database.read(magicCookieByteArray);
	// database.read(recordLengthByteArray);
	// database.read(numberOfFieldsByteArray);
	//
	// final int magicCookie = getValue(magicCookieByteArray);
	// final int recordLength = getValue(recordLengthByteArray);
	// final int numberOfFields = getValue(numberOfFieldsByteArray);
	//
	// String message = "Magic cookie: " + magicCookie;
	// System.out.println(message);
	//
	// message = "Record length: " + recordLength;
	// System.out.println(message);
	//
	// message = "Number of fields in each record: " + numberOfFields;
	// System.out.println(message);
	// System.out.println();
	//
	// final String[] fieldNames = new String[numberOfFields];
	// final int[] fieldLengths = new int[numberOfFields];
	//
	// /*
	// * At this point, the information of each field is provided,
	// * therefore, the main point of this "for" loop is to get the name
	// * and length of each field
	// */
	// for (int i = 0; i < numberOfFields; i++) {
	// final byte nameLengthByteArray[] = new byte[FIELD_NAME_BYTES];
	// database.read(nameLengthByteArray);
	// final int nameLength = getValue(nameLengthByteArray);
	//
	// final byte[] fieldNameByteArray = new byte[nameLength];
	// database.read(fieldNameByteArray);
	// fieldNames[i] = new String(fieldNameByteArray, ENCODING);
	//
	// final byte[] fieldLength = new byte[FIELD_LENGTH_BYTES];
	// database.read(fieldLength);
	// fieldLengths[i] = getValue(fieldLength);
	// }
	//
	// int record = 1;
	//
	// /*
	// * The actual content of each record is read here. The file is read
	// * until EOF is reached.
	// */
	// while (true) {
	// final byte[] flagByteArray = new byte[RECORD_FLAG_BYTES];
	// final int eof = database.read(flagByteArray);
	//
	// if (eof == -1) {
	// break;
	// }
	//
	// final int flag = getValue(flagByteArray);
	//
	// message = "*********** RECORD " + record + " ***********";
	// System.out.println(message);
	//
	// for (int i = 0; i < numberOfFields; i++) {
	// final byte[] buffer = new byte[fieldLengths[i]];
	// database.read(buffer);
	// message = fieldNames[i] + ": "
	// + new String(buffer, ENCODING);
	// System.out.println(message);
	// }
	//
	// if (flag == VALID) {
	// message = "Status: valid record";
	// } else {
	// message = "Status: deleted record";
	// }
	//
	// System.out.println(message);
	// System.out.println();
	// record++;
	// }
	//
	// database.close();
	//
	// } catch (final FileNotFoundException exception) {
	// final String message = "The given file does not exist.";
	// throw new RuntimeException(message, exception);
	// } catch (final IOException exception) {
	// final String message = "The following error occurred while trying "
	// + "to read the database file: " + exception.getMessage();
	// throw new RuntimeException(message, exception);
	// }

    }

    /**
     * Converts to <code>int</code> the content of a given <code>byte</code>
     * array.
     * 
     * @param byteArray
     *            The <code>byte</code> array that contains the number to be
     *            converted.
     * @return An <code>int</code> that represents the content of the
     *         <code>byte</code> array, provided as argument.
     */
    private static int getValue(final byte[] byteArray) {
	int value = 0;
	final int byteArrayLength = byteArray.length;

	for (int i = 0; i < byteArrayLength; i++) {
	    final int shift = (byteArrayLength - 1 - i) * 8;
	    value += (byteArray[i] & 0x000000FF) << shift;
	}

	return value;
    }

    public void read() throws IOException {
	try {
	    File file = new File(DATABASE_LOCATION);
	    RandomAccessFile raf = new RandomAccessFile(file, "rw");

	    int magicCookie = raf.readInt();
	    System.out.println("Magic Cookie: " + magicCookie);

	    int length = raf.readInt();
	    System.out.println("Length: " + length);

	    short numberFields = raf.readShort();
	    System.out.println("Number of Fields: " + numberFields);

	    String[] fieldNames = new String[numberFields];
	    int[] fieldLengths = new int[numberFields];
	    for (int i = 0; i < numberFields; i++) {
		final byte nameLengthByteArray[] = new byte[FIELD_NAME_BYTES];
		raf.read(nameLengthByteArray);
		final int nameLength = getValue(nameLengthByteArray);
		System.out.println("nameLength " + nameLength);

		final byte[] fieldNameByteArray = new byte[nameLength];
		raf.read(fieldNameByteArray);
		fieldNames[i] = new String(fieldNameByteArray, ENCODING);
		System.out.println("fieldName " + fieldNames[i]);

		final byte[] fieldLength = new byte[FIELD_LENGTH_BYTES];
		raf.read(fieldLength);
		fieldLengths[i] = getValue(fieldLength);
		System.out.println("fieldLength " + fieldLengths[i]);
		System.out.println("*************");
	    }
	    int record = 1;
	    while (true) {
		final byte[] flagByteArray = new byte[RECORD_FLAG_BYTES];
		final int eof = raf.read(flagByteArray);

		if (eof == -1) {
		    break;
		}

		final int flag = getValue(flagByteArray);

		String message = "*********** RECORD " + record
			+ " ***********";
		System.out.println(message);

		hotelData = new String[numberFields];
		for (int i = 0; i < numberFields; i++) {
		    byte[] buffer = new byte[fieldLengths[i]];
		    raf.read(buffer);
		    message = fieldNames[i] + ": "
			    + new String(buffer, ENCODING);
		    System.out.println(message);
		    hotelData[i] = new String(buffer, ENCODING).trim();
		}

		if (flag == VALID) {
		    message = "Status: valid record";
		} else {
		    message = "Status: deleted record";
		}
		System.out.println(message);
		System.out.println();

		// put room into map, only if not deleted
		if (flag == VALID) {
		    // roomMap.put(record, hotelData);
		}
		record++;
	    }

	    raf.close();

	} catch (IOException ex) {
	    Logger.getLogger(DataFileReader.class.getName()).log(Level.SEVERE,
		    null, ex);
	}
    }

    /**
     * 
     * Store record in Map only if valid, otherwise put null into the map.
     * 
     * 
     * @throws IOException
     */
    public void readDirectly() throws IOException {

    }

}
